package 动态加载和验证插件;

import java.io.File;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;

public class PluginSystem {

    public static void main(String[] args) throws Exception {
        // 指定插件存放的目录为当前目录下的 "plugins" 文件夹
        File pluginDir = new File("plugins");

        // 如果目录不存在，则创建它，并提示用户放置插件
        if (!pluginDir.exists()) {
            pluginDir.mkdir();
            System.out.println("Please put plugin jars in the plugins directory");
            return;
        }

        // 查找 plugins 目录下所有以 .jar 结尾的文件（即插件JAR）
        File[] jars = pluginDir.listFiles((dir, name) -> name.endsWith(".jar"));

        // 如果没有找到任何 JAR 文件，则提示用户并退出程序
        if (jars == null || jars.length == 0) {
            System.out.println("No plugins found in plugins directory");
            return;
        }

        // 遍历每一个插件 JAR 文件
        for (File jar : jars) {
            try {
                // 将 JAR 文件转换为 URL 格式，供类加载器使用
                URL jarUrl = jar.toURI().toURL();

                // 创建一个自定义的类加载器 URLClassLoader
                // 可以从指定的 JAR 文件中加载类
                URLClassLoader loader = new URLClassLoader(new URL[]{jarUrl});

                // 获取预设的插件类名列表（简化处理，实际应扫描 JAR 或读取配置文件）
                for (String className : getPluginClassNames()) {
                    try {
                        // 使用反射加载类
                        Class<?> pluginClass = Class.forName(className, true, loader);

                        // 判断这个类是否实现了 Plugin 接口
                        if (Plugin.class.isAssignableFrom(pluginClass)) {
                            // 获取无参构造方法
                            Constructor<?> ctor = pluginClass.getDeclaredConstructor();

                            // 使用反射创建插件实例
                            Plugin plugin = (Plugin) ctor.newInstance();

                            // 调用插件的方法
                            System.out.println("Loaded plugin: " + plugin.getName());
                            plugin.execute();
                        }
                    } catch (ClassNotFoundException e) {
                        // 忽略找不到的类，继续尝试下一个类名
                    }
                }

                // 关闭类加载器释放资源（可选，但在长期运行的系统中很重要）
                loader.close();

            } catch (Exception e) {
                // 捕获异常并打印错误信息
                System.err.println("Failed to load plugin from " + jar.getName());
                e.printStackTrace();
            }
        }
    }

    /**
     * 返回插件类的全限定类名数组。
     * 实际项目中可以通过以下方式获取：
     * - 扫描 JAR 包中的 MANIFEST.MF 文件
     * - 使用服务提供者机制（SPI）
     * - 或在每个插件 JAR 中包含配置文件指定类名
     */
    private static String[] getPluginClassNames() {
        return new String[]{
                "com.example.plugins.HelloPlugin",
                "com.example.plugins.GoodbyePlugin"
        };
    }
}